package item28;

import java.util.*;

/**
 * 第28条：利用有限制通配符来提升api的灵活性
 */
public class Main01 {

    public static void main(String[] args) {

        Stack01<Number> numberStack01 = new Stack01<>();
        Iterable<Integer> integers = new Iterable<Integer>() {
            @Override
            public Iterator<Integer> iterator() {
                List<Integer> list = new ArrayList<Integer>();
                list.add(1);
                return list.iterator();
            }
        };
        //不能编译成功
//        numberStack01.pushAll(integers);
        List<Object> objects = new ArrayList<>();
        //不能编译成功
//        numberStack01.popAll(objects);
        Stack02<Number> numberStack02 = new Stack02<Number>();
        numberStack02.pushAll(integers);
        System.out.println(numberStack02.pop());
        numberStack02.push(2);
        numberStack02.popAll(objects);
        System.out.println(objects.get(0));

        // 为了获得最大限度的灵活性，要在表示生产者或者消费者的输入参数上使用通配符类型。
        // PECS表示producer-extends, consumer-super

        // 不要用通配符类型作为返回类型
        // 如果类的用户必须考虑通配符类型，类的api或许就会出错。

        Set<Integer> integers1 = new HashSet<>();
        integers1.add(1);
        integers1.add(2);
        Set<Double> doubles = new HashSet<>();
        doubles.add(2.0);
        doubles.add(3.0);
        Set<Number> numbers = union02(integers1, doubles);
        System.out.println(numbers);
        numbers = Main01.<Number>union02(integers1, doubles);
        System.out.println(numbers);

        // comparable 始终是消费者，因此使用时始终应该是Comparable<? super T>优先于Comparable<T>
        // 对于comparator也一样，因此使用时始终应该是Comparator<? super T> 优先于Comparator<T>
        // 如果类型参数只在方法声明中出现一次，就可以用通配符取代它。
    }

    public static <E> Set<E> union01(Set<E> s1, Set<E> s2) {
        Set<E> result = new HashSet<>(s1);
        result.addAll(s2);
        return result;
    }

    public static <E> Set<E> union02(Set<? extends E> s1, Set<? extends E> s2) {
        Set<E> result = new HashSet<>(s1);
        result.addAll(s2);
        return result;
    }

    public static <T extends Comparable<T>> T max01(List<T> list) {
        Iterator<T> i = list.iterator();
        T result = i.next();
        while (i.hasNext()) {
            T t = i.next();
            if (t.compareTo(result) > 0)
                result = t;
        }
        return result;
    }

    public static <T extends Comparable<? super T>> T max02(List<? extends T> list) {
        Iterator<? extends T> i = list.iterator();
        T result = i.next();
        while (i.hasNext()) {
            T t = i.next();
            if (t.compareTo(result) > 0)
                result = t;
        }
        return result;
    }

}
